package com.homestead.codec;

import com.homestead.utils.ProtoStuffUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import org.redisson.client.codec.BaseCodec;
import org.redisson.client.handler.State;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;

import java.nio.charset.Charset;

/**
 * @author HanBin_Yang
 * @since 2021/3/17 22:14
 */
public class ProtoStuffCodec extends BaseCodec {
    public static final ProtoStuffCodec INSTANCE = new ProtoStuffCodec();

    private final Charset charset;

    private final Encoder valueEncoder = in -> Unpooled.wrappedBuffer(ProtoStuffUtil.serializeByWrapper(in));

    private final Decoder<Object> valueDecoder = (buf, state) -> {
        byte[] result = new byte[buf.readableBytes()];
        buf.readBytes(result);
        return ProtoStuffUtil.deserializeByWrapper(result);
    };

    private final Encoder keyEncoder = new Encoder() {
        @Override
        public ByteBuf encode(Object in) {
            ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
            out.writeCharSequence(in.toString(), charset);
            return out;
        }
    };

    private final Decoder<Object> keyDecoder = new Decoder<Object>() {
        @Override
        public Object decode(ByteBuf buf, State state) {
            String str = buf.toString(charset);
            buf.readerIndex(buf.readableBytes());
            return str;
        }
    };

    public ProtoStuffCodec() {
        this(CharsetUtil.UTF_8);
    }

    public ProtoStuffCodec(Charset charset) {
        this.charset = charset;
    }

    @Override
    public Decoder<Object> getValueDecoder() {
        return this.valueDecoder;
    }

    @Override
    public Encoder getValueEncoder() {
        return this.valueEncoder;
    }

    @Override
    public Decoder<Object> getMapValueDecoder() {
        return this.valueDecoder;
    }

    @Override
    public Encoder getMapValueEncoder() {
        return this.valueEncoder;
    }

    @Override
    public Decoder<Object> getMapKeyDecoder() {
        return this.keyDecoder;
    }

    @Override
    public Encoder getMapKeyEncoder() {
        return this.keyEncoder;
    }
}
